<!--
* @Version V1.0
* @Project: MGS平台10.1 All rights Reserved, Designed By www.supermap.com
* @Title: 二维地图
* @Description: 二维地图 组件
* @Author: wanghan
* @Date: Created in 2021-03-15 14:22:49
* @Copyright: 2021 www.supermap.com Inc. All rights reserved.
* 注意：本内容仅限于北京超图信息技术有限公司内部传阅，禁止外泄以及用于其他的商业目
-->
<template>
    <div ref="map" class="mgs-l-map" v-once />
</template>

<script lang="ts">
import type { View } from 'types'

import { Component, Prop, Mixins, Watch } from 'vue-property-decorator'

import ViewMixin from './view-mixin'
import LayerMixin from './layer-mixin'
import DrawMixin from './draw-mixin'
import InteractionMixin from './interaction-mixin'
import PluginMixin from '@/mixins/plugin-mixin'

import L from 'leaflet'
import { compareView, getView } from '@/utils/view'

//地图服务默认配置
function getDefOptions() {
    return {
        preferCanvas: true,
        crs: L.CRS.EPSG3857,
        center: [0, 0],
        zoom: 1,
        maxZoom: 21,
        dragging: true,
        touchZoom: true,
        zoomControl: false,
        attributionControl: false,
    }
}

@Component
export default class MgsLMap extends Mixins(
    ViewMixin,
    LayerMixin,
    DrawMixin,
    InteractionMixin,
    PluginMixin
) {
    // 读取指定目录插件
    readonly PluginClazzes = require.context('./plugins/', false, /.ts$/)

    // 地图类型
    readonly MapType = '2D'

    /**
     * 是否显示 superMap Logo
     */
    @Prop({ type: Boolean, default: false })
    logo!: boolean

    /**
     * 地图初始化参数（详细请看 `L.MapOptions`）
     */
    @Prop({ type: Object, default: () => ({}) })
    options!: L.MapOptions

    /**
     * 图幅中心点和缩放（支持sync参数）
     */
    @Prop(Object)
    view?: View
    private viewDirty = true

    /**
     * 是否联动move事件（即每次move都同步视图 view，而不是moveend）
     * 这会对性能有损耗
     */
    @Prop({ type: Boolean, default: false })
    linkMove?: boolean

    mounted() {
        this.$nextTick(() => {
            const map = L.map(
                this.$refs.map as HTMLElement,
                Object.assign(getDefOptions(), this.options)
            )
            ;(map as any)._isVue = true
            this.map = map

            // 初始化draw图层
            this._initDrawMixin(map)
            // 初始化选择器相关
            this._initInteractionMixin(map)

            // 同步地图事件
            this.syncEvents(map)

            // 初始化视图
            this.viewWatcher(this.view)

            // 加载插件
            this._loadPlugins()

            // 去除logo
            if (!this.logo) {
                const logo = this.$el.querySelector('.iclient-leaflet-logo')
                logo && logo.remove()
            }

            /**
             * 地图初始化完毕
             */
            this.$emit('onMapInited', this)
        })
    }

    beforeDestroy() {
        this.map.remove()
        this.map = undefined as any
    }

    @Watch('view', { deep: true })
    viewWatcher(nvl?: View) {
        // 不存在视图
        if (!this.map || !nvl) return

        // 视图不一致
        if (this.viewDirty && compareView(nvl, getView(this.map))) {
            this.viewDirty = false
            this.zoom2Centoid(nvl.center, { zoom: nvl.zoom, duration: 0 })
        }
    }

    private syncEvents(map: L.Map) {
        // 视图更新事件
        const viewChangeHandler = () => {
            if (!this.viewDirty) {
                this.viewDirty = true
                return
            }

            // 更新中心点 同步视图
            const view = getView(this.map)
            if (compareView(this.view, view)) {
                this.viewDirty = false
                this.$emit('update:view', view)
                this.$nextTick(() => (this.viewDirty = true))
            }
        }
        // 同步视图更新
        map.on({
            moveend: viewChangeHandler,
            // 缩放
            zoomend: () => {
                /**
                 * 地图缩放结束
                 */
                this.$emit('onZoomEnd')
            },
        })

        // 移动事件
        if (this.linkMove) {
            map.on('move', viewChangeHandler)
        }
    }
}
</script>

<docs>
## Demo

::: demo

<template>
    <mgs-l-map
        style="height: 500px; width: 100%;"
        :view.sync="view"
        :options="options"
        @onMapInited="initMap"
    />
</template>

<script>
export default {
    data() {
        return {
            // 中心点设置（双向绑定）
            view: { center: [108, 40], zoom: 3 },
            // 地图参数
            options: {
                preferCanvas: true,
                crs: L.CRS.EPSG3857,
            },
        }
    },
    methods: {
        initMap(bindMap) {
            bindMap.addService(
                '1',
                'arcgisrestmap',
                'https://server.arcgisonline.com/arcgis/rest/services/Specialty/DeLorme_World_Base_Map/MapServer'
            )
        }
    }
}
</script>

:::
</docs>
